package com.dycx.api.config;

import com.dycx.common.ThreadLocalUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
@Aspect
@Order(1)
public class TrimAspect {
    public ArrayList<String> al;

    // 定义切点
    // 记录后台接口的操作记录
    // 拦截Controller所在的包
    @Pointcut("execution(public * com.dycx.api.controller.*.*.*.*(..))")
    public void excudeService() {
    }

    @Around("excudeService()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        this.al = new ArrayList<>();

        //重点 这里就是获取@RequestBody参数的关键  调试的情况下 可以看到arr变量已经获取到了请求的参数
        Object[] arr = pjp.getArgs();
        for (int i = 0; i < arr.length; ++i) {
            if (arr[i] instanceof HttpServletRequest) { // 特殊处理
                HttpServletRequest request = (HttpServletRequest) arr[i];
                Map<String, String[]> m = request.getParameterMap();
                Map<String, String[]> newM = new HashMap<String, String[]>();
                if (m != null) {
                    for (Map.Entry<String, String[]> entry : m.entrySet()) {
                        String key = entry.getKey();
                        String[] value = entry.getValue();
                        if (value == null) continue;
                        for (int j = 0; j < value.length; ++j) {
                            String temp = value[i].trim();
                            value[i] = temp.length() == 0 ? null : temp;
                        }
                        newM.put(key, value);
                    }
                }
                // 因为我们无法去改变getParameterMap的返回值
                // 所以对里面值去除空的格是无效的
                // 但是我们可以把参数的值去除空格之后把值放入setAttribute里面
                // 这样request对象就携带了去除空格之后的值
                request.setAttribute("The-result-after-removing-the-space", newM);
                arr[i] = request;
            } else {
                // 考虑到类里面还有类 这里采用递归的方式处理
                if (null != arr[i]) {
                    arr[i] = dfs(arr[i].getClass(), arr[i]);
                }
            }
        }

        // 把 arr 放回去即可改变参数的值
        return pjp.proceed(arr);
    }

    private Object dfs(Class<?> aClass, Object object) throws IllegalAccessException {
        if (object == null) return null;
        // 判断是否为Java的基本类型或包装类
        if (isPrimitive(aClass)) {
            if (object instanceof String) {
                return ((String) object).trim();
            } else if (object instanceof List<?>) {
                //List中是字符串的话需要特殊处理，如果是对象List的话递归
                List<Object> result = new ArrayList<>();
                for (Object o : (List<?>) object) {
                    if (isPrimitive(o.getClass())) {
                        if (o instanceof String) {
                            o = ((String) o).trim();
                            result.add(o);
                        } else if (isPrimitive(o.getClass())) {
                            result.add(o);
                        }
                    } else {
                        result.add(dfs(o.getClass(), o));
                    }
                }
                return result;
            }
            return object;
        }
        // 返回类所有字段
        // 注意： 会返回静态字段
        // 不要在Dto、Vo定义静态属性
        // 没有获取父类属性 可通过 “object.getClass().getSuperclass()” 获取
        for (Field item : object.getClass().getDeclaredFields()) {
            // static修饰的字段忽略
            if (Modifier.isStatic(item.getModifiers())) {
                continue;
            }
            // 设置可见性
            item.setAccessible(true);

            // 递归处理
            Object val = item.get(object);
            Object childObj = dfs(item.getType(), val);
            item.set(object, childObj);

            //************添加签名参数start****************
            boolean isObject = false;
            if (childObj instanceof ArrayList<?>) {
                for (Object o : (List<?>) childObj) {
                    if (!isPrimitive(o.getClass())) {
                        isObject = true;
                    }
                    break;
                }
                val = val.toString().replace(" ", "");
            }
            if (val != null && val != "" && !isObject && val.toString() != "[]") {
                this.al.add(item.getName() + "=" + val.toString());
            }

            //************添加签名参数end****************
        }
        return object;
    }

    // 判断是否为Java的基本类型或包装类
    // java.lang.* java.util.* 存放着Java的基本数据类型的包装类和集合类
    // 基本数据类型和包装类是JVM虚拟机运行需要的类，已嵌入到JVM内核
    // 不需要继承ClassLoader 用户自定义的需要
    private boolean isPrimitive(Class<?> aClass) {
        return aClass != null && aClass.getClassLoader() == null;
    }

}
